package fr.pud.utils;

import java.awt.Color;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Vector;

import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.openstreetmap.gui.jmapviewer.DefaultMapController;

import com.apple.eawt.Application;

import fr.pud.client.LaunchProgram;
import fr.pud.client.i18n.LanguagesConstants;
import fr.pud.client.images.ImagesDatabase;

/**
 * This class implements some tools which can be used in different contexts for
 * example the language initialization.
 * @author Pierre Reliquet
 */
public class Tools {
    public static Vector<String> TIMES_DATABASE = new Vector<String>();
    static {
        for (int hour = 07; hour <= 23; hour++) {
            TIMES_DATABASE.add(hour + ":00");
            TIMES_DATABASE.add(hour + ":30");
        }
        for (int hour = 0; hour <= 06; hour++) {
            TIMES_DATABASE.add(hour + ":00");
            TIMES_DATABASE.add(hour + ":30");
        }
    }
    /**
     * An array which contains the usual colors
     */
    public static final Color[] COLORS = {
            Color.RED, Color.MAGENTA, Color.BLUE, Color.CYAN, Color.ORANGE,
            Color.GREEN, Color.PINK, Color.YELLOW, Color.BLACK, Color.WHITE,
            Color.DARK_GRAY
    };
    /**
     * The URL for the open street map server
     */
    public static final String OPEN_STREET_MAP = "http://www.openstreetmap.org";
    /**
     * The URL for the nominatim database
     */
    public static final String NOMINATIM = "http://nominatim.openstreetmap.org/";
    /**
     * Constant to disable the JOptionPane
     */
    public static final boolean LOG_FILE_NO_JOPTION_PANE = false;
    /**
     * Constant to enable the joptionpane
     */
    public static final boolean LOG_FILE_SHOW_JOPTION_PANE = true;
    /**
     * A file to create a new folder called PUD
     */
    private static File LOG_FILE_FOLDER = new File(
            LanguagesConstants.LANGUAGE
                    .getString(LanguagesConstants.FOLDER_NAME_PUD_LOG));
    /**
     * A file to create a new folder called DATA
     */
    public static File DATA_FILE_FOLDER = new File(
            LanguagesConstants.LANGUAGE
                    .getString(LanguagesConstants.FOLDER_NAME_PUD_DATA));
    /**
     * The path of the logFile
     */
    public static File LOG_FILE;
    /**
     * The name of the file
     */
    private static final String LOG_FILE_NAME = "/log_file_";
    /**
     * An instance of fileWriter to write into the logFile
     */
    public static FileWriter LOG_FILE_ERRORS;
    /**
     * A boolean to know if the logFile is created
     */
    public static boolean FILE_IS_CREATED = false;
    public static boolean FOLDER_IS_CREATED;
    /**
     * The separator between the languages in the file languages.lang
     */
    public static final char LANGUAGE_SEPARATOR = '|';

    /**
     * This method changes the menu bar for the Mac Os X system.
     */
    public static void changeMenuBar() {
        if (DefaultMapController.isPlatformOsx()) {
            // System.setProperty("apple.laf.useScreenMenuBar", "true");
            // System.setProperty(
            // "com.apple.mrj.application.apple.menu.about.name",
            // LanguagesConstants.LANGUAGE
            // .getString(LanguagesConstants.TITLE));
            System.setProperty("apple.laf.useScreenMenuBar", "true");
            System.setProperty(
                    "com.apple.mrj.application.apple.menu.about.name", "Test");
            try {
                UIManager.setLookAndFeel(UIManager
                        .getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException e1) {
                e1.printStackTrace();
            } catch (InstantiationException e1) {
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                e1.printStackTrace();
            } catch (UnsupportedLookAndFeelException e1) {
                e1.printStackTrace();
            }
            Application application = Application.getApplication();
            Image imageDock = null;
            try {
                imageDock = Toolkit.getDefaultToolkit().getImage(
                        LaunchProgram.class.getResource("images/osmIcon.png"));
            } catch (Exception e) {
                writeToLogFile(
                        "osmIcon.png "
                                + LanguagesConstants.LANGUAGE
                                        .getString(LanguagesConstants.ERROR_FILE),
                        false);
            }
            application.setDockIconImage(imageDock);
        }
    }

    public static void createFolders(File pathFolder) {
        try {
            if (!pathFolder.exists()) {
                FOLDER_IS_CREATED = pathFolder.mkdirs();
                if (!FOLDER_IS_CREATED) {
                    JOptionPane
                            .showMessageDialog(
                                    null,
                                    pathFolder.getAbsolutePath()
                                            + LanguagesConstants.LANGUAGE
                                                    .getString(LanguagesConstants.ERROR_FOLDER),
                                    LanguagesConstants.LANGUAGE
                                            .getString(LanguagesConstants.ERROR_OCCURED),
                                    JOptionPane.ERROR_MESSAGE);
                }
            }
        } catch (Exception e) {
        }
    }

    /**
     * Create a hideen file
     * @throws IOException
     */
    public static void createHiddenFile(File f) throws IOException {
        if (!f.isHidden() && Tools.isPlatformWindows()) {
            String[] cmd = {
                    "attrib", "+H", f.getAbsolutePath()
            };
            Process process = Runtime.getRuntime().exec(cmd);
            process.getOutputStream().close();
            process.getErrorStream().close();
        }
    }

    /**
     * @return an HashMap<String,String> where the keys are the values contained
     *         in the first column of the language file and the value are in the
     *         column which corresponds to the language (default english)
     * @deprecated
     */
    @Deprecated
    public static HashMap<String, String> initializeLanguage() {
        String pathLanguageFile = "../languages/languages.lang";
        HashMap<String, String> lang = new HashMap<String, String>();
        try {
            Scanner scan = new Scanner(new File(pathLanguageFile));
            String systemLanguage = System.getProperty("user.language");
            int indexOfLanguage = 0;
            if (scan.hasNextLine()) {
                String line = scan.nextLine();
                ArrayList<String> list = parseString(line, LANGUAGE_SEPARATOR);
                indexOfLanguage = list.indexOf(systemLanguage);
                if (indexOfLanguage == -1) {
                    indexOfLanguage = 1;
                }
            } else {
                printErrorAndExit("The lang file does not exist",
                        "Error with languages");
            }
            while (scan.hasNextLine()) {
                String line = scan.nextLine();
                ArrayList<String> list = parseString(line, LANGUAGE_SEPARATOR);
                lang.put(list.get(0), list.get(indexOfLanguage));
            }
        } catch (IOException e) {
            printErrorAndExit("An error occured with the language file",
                    "Error with languages");
        }
        return lang;
    }

    /**
     * Initialize the creation of the logFile
     * @throws IOException
     */
    public static void initLogFile() throws IOException {
        // Define the format of the date used inside the logFile name
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "d MMMM yyyy HH:mm:ss");
        // The date of the logFile creation
        String date = dateFormat.format(new Date()).toString();
        date = date.replaceFirst(":", "h");
        date = date.replaceFirst(":", "m");
        date = date.replaceAll(" ", "-");
        try {
            createFolders(LOG_FILE_FOLDER);
            createFolders(DATA_FILE_FOLDER);
            // creation of the logFile
            LOG_FILE = new File(LOG_FILE_FOLDER.getAbsolutePath()
                    + LOG_FILE_NAME + date + ".txt");
            LOG_FILE_ERRORS = new FileWriter(LOG_FILE);
        } catch (Exception e) {
            JOptionPane
                    .showMessageDialog(
                            null,
                            "fileLog.txt "
                                    + LanguagesConstants.LANGUAGE
                                            .getString(LanguagesConstants.ERROR_FILE),
                            "fileLog.txt "
                                    + LanguagesConstants.LANGUAGE
                                            .getString(LanguagesConstants.ERROR_OCCURED),
                            JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * This method is used to test the internet connection to be sure that the
     * programm won't launch if there is no internet on the computer
     * @return true is nominatim and osm are reachable
     */
    public static boolean isConnected() {
        try {
            @SuppressWarnings("unused")
            InputStream response;
            URL nominatim = new URL(NOMINATIM);
            URLConnection nominatimConnection = nominatim.openConnection();
            nominatimConnection
                    .setConnectTimeout(Conversion.TIMEOUT_CONNECTION);
            response = nominatimConnection.getInputStream();
            URL osm = new URL(OPEN_STREET_MAP);
            URLConnection osmConnection = osm.openConnection();
            osmConnection.setConnectTimeout(Conversion.TIMEOUT_CONNECTION);
            response = osmConnection.getInputStream();
        } catch (MalformedURLException e) {
            e.printStackTrace();
            Tools.writeToLogFile(
                    "Please check the URL to test the internet connection",
                    LOG_FILE_NO_JOPTION_PANE);
            return false;
        } catch (IOException e) {
            Tools.writeToLogFile(LanguagesConstants.LANGUAGE
                    .getString(LanguagesConstants.NO_CONNECTION),
                    LOG_FILE_SHOW_JOPTION_PANE, e.getStackTrace());
            return false;
        }
        return true;
    }

    public static boolean isPlatformLinux() {
        String os = System.getProperty("os.name");
        return os != null && os.toLowerCase().startsWith("linux");
    }

    public static boolean isPlatformWindows() {
        String os = System.getProperty("os.name");
        return os != null && os.toLowerCase().startsWith("windows");
    }

    /**
     * @param completeString
     *            a line where data is separated by the char separator
     * @param separator
     *            , the separator between two data fields
     * @return an ArrayList<String> , with each data in a specific position
     *         (similarity with an array)
     */
    public static ArrayList<String> parseString(String completeString,
            char separator) {
        ArrayList<String> listString = new ArrayList<String>();
        String s = "";
        for (int i = 0; i < completeString.length(); i++) {
            if (completeString.charAt(i) == separator) {
                listString.add(s);
                s = "";
            } else {
                s += completeString.charAt(i);
            }
        }
        return listString;
    }

    /**
     * Print an error message with a JOptionPane
     * @param message
     *            , the error message
     * @param title
     *            , the title of the error pane
     */
    public static void printErrorAndExit(String message, String title) {
        JOptionPane.showMessageDialog(null, message, title,
                JOptionPane.ERROR_MESSAGE);
        try {
            LOG_FILE_ERRORS.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.exit(-1);
    }

    /**
     * Write in the log the file all the address of the user
     * @param addressesList
     *            , The list of address to write inside the file
     */
    public static void saveObject(Object anObject, String fileName,
            String extension) {
        try {
            File f = new File(
                    LanguagesConstants.LANGUAGE
                            .getString(LanguagesConstants.FOLDER_NAME_PUD_DATA)
                            + "/" + fileName + "." + extension);
            FileOutputStream fileOutput = new FileOutputStream(f);
            ObjectOutputStream oos = new ObjectOutputStream(fileOutput);
            oos.writeObject(anObject);
            oos.flush();
            oos.close();
        } catch (IOException e) {
            Tools.writeToLogFile("File could not be created", false,
                    e.getStackTrace());
        }
    }

    /**
     * This method write in the logFile the string which is in parameter
     * @param toWrite
     *            , the string to write in the logfile
     * @param toWriteToJOP
     *            , if the value of this boolean = true, the message will be
     *            show to the user with a JOptionPane
     */
    public static void writeToLogFile(String toWrite, boolean toWriteToJOP) {
        if (FILE_IS_CREATED == false) {
            try {
                initLogFile();
                FILE_IS_CREATED = true;
            } catch (IOException e) {
                JOptionPane.showMessageDialog(null,
                        "Impossible to create the log file",
                        LanguagesConstants.LANGUAGE
                                .getString(LanguagesConstants.ERROR_OCCURED),
                        JOptionPane.ERROR_MESSAGE);
            }
        }
        try {
            LOG_FILE_ERRORS.append(toWrite);
            LOG_FILE_ERRORS.append("\n");
            LOG_FILE_ERRORS.flush();
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null,
                    "Impossible to write in the file",
                    LanguagesConstants.LANGUAGE
                            .getString(LanguagesConstants.ERROR_OCCURED),
                    JOptionPane.ERROR_MESSAGE);
        }
        if (toWriteToJOP) {
            JOptionPane.showMessageDialog(null, toWrite,
                    LanguagesConstants.LANGUAGE
                            .getString(LanguagesConstants.ERROR_OCCURED),
                    JOptionPane.ERROR_MESSAGE, ImagesDatabase.OSM_ICON);
        }
    }

    /**
     * This method write in the logFile the string which is in parameter
     * @param toWrite
     *            , the string to write in the logfile
     * @param toWriteToJOP
     *            , if the value of this boolean = true, the message will be
     *            show to the user with a JOptionPane
     */
    public static void writeToLogFile(String toWrite, boolean toWriteToJOP,
            StackTraceElement[] elem) {
        writeToLogFile(toWrite, toWriteToJOP);
        for (int i = 0; i < elem.length; i++) {
            writeToLogFile("\t" + elem[i].toString(), LOG_FILE_NO_JOPTION_PANE);
        }
    }

    public static void removeLinesWithCapsMiddleWordsFromFile(String fileName,String extension) {
        String caps = ".*[a-zA-Z][a-z]*[A-Z][a-z0-9]*";
        char newLine = '\n';
        String tab = "\t";
        String space = " ";
        try {
            Scanner scan = new Scanner(new FileReader(fileName+((extension.length()>0)?"."+extension:"")));
            FileWriter fw = new FileWriter(fileName+"_noCaps"+((extension.length()>0)?"."+extension:""));
            while(scan.hasNextLine()) {
                String line = scan.nextLine();
                line = line.replace(tab,space);
                line = line.replace(space+space, space);
                if(!line.matches(caps)) {
                    fw.write(line+newLine);
                    fw.flush();
                }
            }
            scan.close();
            fw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        removeLinesWithCapsMiddleWordsFromFile("rgb", "txt");
    }
}
